package caras;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.MemoryImageSource;
import hypermedia.video.*;

import processing.core.PFont;
import processing.core.PMatrix2D;;	// all processing functionality

public class BlobDetection extends Frame implements Runnable {
	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	// program execution frame rate (millisecond)
	final int FRAME_RATE  = 1000/30;
	// threshold value for removing noises
	final float THRESHOLD = 80f; 
	
	
	OpenCV cv = null;	// OpenCV Object
	Thread t  = null;	// the program thread
	
	// camera width/height
	int capture_width = 320;
	int capture_height = 240;

	// threshold for background subtraction
	int threshold = 125;

	// some variables to control the contrast/brightness of the camera image
	int contrast = 0, brightness = 0;

	// for drawing text
	PFont font;

	// these boolean values will be used to trigger parts of the code - we
	// can use the keyPressed method to set these boolean values with the keyboard
	boolean draw_blobs=true, draw_centroid=true, show_difference=true;

	// we are going to track the centroid of all blobs and keep the previous
	// and current estimate
	int previous_centroid_x = capture_width / 2;
	int previous_centroid_y = capture_height / 2;
	int current_centroid_x = capture_width / 2;
	int current_centroid_y = capture_height / 2;

	
	// the input video stream image
	Image frame	 = null;
	Blob[] blobs = null;
	
	
	/*public void setup()	{
		// Size of the window
		size(capture_width*4, capture_height+20);

		// Instantiate opencv with an instance of our applet
		cv = new OpenCV(this);

		// Setup our capture device using opencv
		cv.capture(capture_width, capture_height, 0);

		// Setup our face detection (take a look at the other CASCADE's such as
		// FULLBODY, UPPERBODY, FRONTALFACE_ALT...
		cv.cascade(OpenCV.CASCADE_FRONTALFACE_DEFAULT);

		// Setup font to use the Andale Mono type font (this file is in the data folder)
		font = loadFont("AndaleMono.vlw");
		textFont(font);
	}
	*/
	/**
	 * Setup Frame and Object(s).
	 */
	BlobDetection() {
		
		super( "Blob Detection Sample" );
		
		
		// OpenCV setup
		cv = new OpenCV();
		cv.capture( capture_width, capture_height,0 );
		cv.cascade( OpenCV.CASCADE_FRONTALFACE_DEFAULT );
		
		
		// frame setup
		this.setBounds( 100, 100, cv.width, cv.height );
		this.setBackground( Color.BLACK );
		this.setVisible( true );
		this.addKeyListener(
			new KeyAdapter() {
				public void keyReleased( KeyEvent e ) { 
					if ( e.getKeyCode()==KeyEvent.VK_ESCAPE ) { // ESC : release OpenCV resources
						t = null;
						cv.dispose();
						System.exit(0);
					}
					if ( e.getKeyCode()==KeyEvent.VK_SPACE ) // SPACE : record background
						cv.remember();
				}
			}
		);
		
		
		// start running program
		t = new Thread( this );
		t.start();
		
	}
	
	
	
	/**
	 * Release OpenCV resources.
	 */
	public void stop() {
		t = null;
		cv.dispose();
	}
	
	
	/**
	 * Draw video frame and each detected faces area.
	 */
	public void paint( Graphics g ) {
		if ( frame==null || blobs==null ) return;
		
		// draw image
		g.drawImage( frame, 0, 0, null );
		
		// draw blobs
		for( Blob b : blobs ) {
			
			Rectangle bounding_box = b.rectangle;
			g.setColor(Color.red);
			g.drawRect(bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height);
			
			/*// define blob's contour
			Polygon shape = new Polygon();
			for( Point p : b.points ) shape.addPoint( p.x, p.y );
			
			// fill blob
			g.setColor( b.isHole ? Color.black : Color.BLUE );
			g.fillPolygon( shape );*/
		}
	}
	
	
	
	//public void doBlobDetection1() {

	/*	// Do the blob detection
		Blob[] blobs = cv.blobs(100, capture_width*capture_height/3, 5, false);
		 public Blob[] blobs(int minArea,
                    int maxArea,
                    int maxBlobs,
                    boolean findHoles) 

		// Pushing a matrix allows any transformations such as rotate, translate, or scale,
		// to stay within the same matrix.  once we "popMatrix()", then all the commands for that matrix
		// are gone for any subsequent drawing.
		pushMatrix();
		// since we translate after we pushed a matrix, every drawing command afterwards will be affected
		// up until we popMatrix().  then this translate will have no effect on drawing commands after
		// the popMatrix().
		translate(capture_width*2, 0);

		// We are going to keep track of the total x,y centroid locations to find
		// an average centroid location of all blobs
		int total_x = 0;
		int total_y = 0;		

		// we loop through all of the blobs found by cv.blobs(..)
		for( int blob_num = 0; blob_num < blobs.length; blob_num++ ) {

			if(draw_blobs)
			{
				// get the bounding box from the blob detection and draw it
				Rectangle bounding_box = blobs[blob_num].rectangle;
				noFill();
				stroke(128);
				this.rect( bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height );
			}

			// accumulate the centroids
			Point centroid = blobs[blob_num].centroid;
			total_x += centroid.x;
			total_y += centroid.y;
		}

		if(blobs.length > 0)
		{
			// by keeping the previous centroid, we can do an interpolation between
			// the current centroid and the previous one.  this will make any tracking results
			// seem smoother.  a better way would be to use a low pass filter over a vector
			// of centroid locations.  i.e. keep more than just 1 previous location and 
			// find a better way of interpolating the current centroid from them.
			previous_centroid_x = current_centroid_x;
			previous_centroid_y = current_centroid_y;

			current_centroid_x = (total_x/blobs.length + previous_centroid_x) / 2;
			current_centroid_y = (total_y/blobs.length + previous_centroid_x) / 2;
		}

		if(draw_centroid)
		{
			// draw a crosshair at the centroid location
			this.ellipse(current_centroid_x, current_centroid_y, 5, 5);
			this.line( current_centroid_x-5, current_centroid_y, current_centroid_x+5, current_centroid_y );
			this.line( current_centroid_x, current_centroid_y-5, current_centroid_x, current_centroid_y+5 );
		}*/
	//	popMatrix();*/
//	}
	
	/**
	 * Execute this sample.
	 */
	public void run() {
		while( t!=null && cv!=null ) {
			try {
				t.sleep( FRAME_RATE );
				
				// grab image from video stream
				cv.read();
				//cv.flip( OpenCV.FLIP_HORIZONTAL );
				
			  // adjust the Contrast/Brightness (stored in OpenCV.BUFFER)
				cv.contrast(contrast);
				cv.brightness(brightness);
				//cv.convert(OpenCV.GRAY);
				
				// create a new image from cv pixels data
				MemoryImageSource mis = new MemoryImageSource( cv.width, cv.height, cv.pixels(), 0, cv.width );
				frame = createImage( mis );
				
				// prepare image for detection
				cv.absDiff();
				cv.convert(cv.GRAY);
				cv.threshold( THRESHOLD );
				
				//Blob[] blobs = cv.blobs(100, capture_width*capture_height/3, 5, false);
				
				// detect blobs
				blobs =  cv.blobs(50, capture_width*capture_height/5, 1, false);
				
				//blobs = cv.blobs( 100, cv.width*(cv.height/2), 5, false);
				Graphics g = getGraphics();
				if ( blobs.length>0) {
					
				// we loop through all of the blobs found by cv.blobs(..)
				for( int blob_num = 0; blob_num < blobs.length; blob_num++ ) {
					
					System.out.println("blop "+blob_num);
					// we loop through all of the blobs found by cv.blobs(..)
					for( int x = 0; x < blobs[blob_num].points.length; x++ )
					{
						System.out.println("x "+blobs[blob_num].points[x].x);
						System.out.println("y "+blobs[blob_num].points[x].y);
					}
					
					//blobs[1].rectangle( bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height );
					// accumulate the centroids
					//Point centroid = blobs[blob_num].centroid;
					/*total_x += centroid.x;
					total_y += centroid.y;*/
				}
				}
				// of course, repaint
				repaint();
				
			}
			catch( InterruptedException e ) {;}
		}
	}
	
	
	/**
	 * Main method.
	 * @param String[]	list of arguments's user passed from the console to this program
	 */
	public static void main( String[] args ) {
		System.out.println( "\nOpenCV blob detection sample" );
		System.out.println( "PRESS SPACE BAR TO RECORD BACKGROUND IMAGE\n" );
		String a= System.getProperty("java.library.path");
		System.out.println(a);
		new BlobDetection();
		
	} 

}